/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/



#if !defined(AFX_PGLLINE2DLOD_H__56F09710_E27C_452B_A49B_78D72EAA6CB2__INCLUDED_)
#define AFX_PGLLINE2DLOD_H__56F09710_E27C_452B_A49B_78D72EAA6CB2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <pgl/core/PGLLine2D.h>
#include <pgl/core/PGLDataVectors.h>


/*! \brief A 2D curve class with Level of Detail capabilities

\ingroup PGLLineGroup

 The curve is represented by a serie of points, wich are given by the user.
All the memory handling is taken care of by PGL.

The user sets a tolerance parameter for the approximated curve. The apprimation
algorithm is based on Douglas-Peukler algorithm. The DP line simplification algorithm was originaly proposed in [1]. 
John Hershberger and Jack Snoeyink have implemented it in C in [2] as a package named DPSimp:

<em>DPsimp is a Douglas-Peucker line simplification alogorithm implementation 
by John Hershberger and Jack Snoeyink. They analyze the line simplification 
algorithm reported by Douglas and Peucker and show that its worst case is quadratic in n, the number of input points. The algorithm is based on path hulls, that uses the geometric structure of the problem to attain a worst-case running time proportional to nlog_2(n), which is the best case of the Douglas algorithm.
</em>

\b Example: How to plot a function f(x) ?
<ol>
<li>Generate pair of points (x,f(x))
\code
int nPoints= // number of poitns
vector<double> vX(nPoints);
vector<double> vY(nPoints);

// Generating data
for (int i=0;i<nPoints;i++)
{
    vX[i]= // put your function here
    vY[i]= // put your function here
}
\endcode
<li> Create line CPGLLine2DLOD object and assign data to it.
\code
	CPGLLine2DLOD* pLine2DLOD=new CPGLLine2DLOD();
	pLine2D->SetDatas(vX,vY);
\endcode
<li>Change tolerance parameter:
\code 
	pLine2DLOD->SetTol(0.0001);
\endcode
<li>Add this line a CPGLGraph object.
\code
    CPGLRegion* pRegion;
	...
	pRegion->AddObject(pLine2DLOD);
\endcode
</ol>

\b Reference:
<ul>
<li>[1] D. H. Douglas and T. K. Peucker. Algorithms for the reduction of the number of points required to represent a line or its caricature. The Canadian Cartographer, 10(2):112--122, 1973.
<li>[2] J. Hershberger and J. Snoeyink. Speeding up the Douglas-Peucker line simplification algorithm. In Proc. 5th Intl. Symp. Spatial Data Handling. IGU Commission on GIS, pages 134--143, 1992. (home page)
</ul>
\sa CPGLLine2D
\sa CPGLLine
\sa CPGLRegion
*/
class PGLCORE_EXT_CLASS CPGLLine2DLOD : public CPGLLine2D  
{
public:
	PGL_DECLARE_DYNCREATE(CPGLLine2DLOD);

	typedef hull::CDPHullF LineApprox;

    //! \name Constructors
    //@{
    //! default constructor
    CPGLLine2DLOD();
    //! copy constructor
    CPGLLine2DLOD(const CPGLLine2DLOD& l){ *this=l;};
    //! assignement constructor
    CPGLLine2DLOD& operator=(const CPGLLine2DLOD& l) ;
    //! desctructor
	virtual ~CPGLLine2DLOD();
	//@}

	//! \name Hull methods
	//@{

	//! returns a pointer to the hull object
	LineApprox& GetHull()		{	return m_hull;};

	//! return a reference to the hull object, const
	const LineApprox& GetHull() const {	return m_hull;};

	/// Sets the tolerance of approximation
	void SetTol(float tol);
	/// return tolerance of approximation
	float GetTol() const	{	return m_hull.GetTol();};

	/*! \brief Make the approximated curve dScale smaller than the original

	Searches for an optimal tolerance to have dScale points in the approximated curve. (using dichotomy method)

	\param dScale compression level from 0, maximum compression to 1 no compression.
	\param dScaleTol [optional] tolerance around compression level, default is 0.05,
	\param nMaxIter [optional] maximum number of iteration in the search algorithm, default is 100,
	\return number of iterations
	*/
	size_t ShrinkNorm( float fScale, float fScaleTol = 0.05, size_t nMaxIter = 100);

	/*! \brief Make the approximated curve 

	\return number of iterations
	*/
	size_t Shrink( size_t nDesiredPoints, size_t nTol = 10, size_t nMaxIter = 100);

	//! rebuilds the hull	
	void ResetHull();
	//@}

	//! \name GUI
	//@{
    //! adds context menu items...
    virtual void AddContextMenuItems(CMenu* pMenu);
    //! adds the Line2D property page to the property dialog
    virtual void AddPropertyPage(CPropertySheet* pPropSheet);
	//@}

	//! \name Data manipulation
	//@{
	/*! Setting the data

	Sets pX and pY as the vector of data. Previous data, if any, is deleted. pX and pY must have been allocated on the heap.
	*/
	virtual void SetDatas(CPGLDataPtr pX, CPGLDataPtr pY);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<double>& vx, const std::vector<double>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<float>& vx, const std::vector<float>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<int>& vx, const std::vector<int>& vy, bool bMakeCopy = true);
	/*! Setting data as vectors of double

	This is a helper function that uses the generic form of SetDatas and spares the user the creation of CPGLData objects.
	\param bMakeOwnCopy if true, a copy of the data is stored, otherwize only the reference is stored (default is true)
	*/
    virtual void SetDatas(const std::vector<BYTE>& vx, const std::vector<BYTE>& vy, bool bMakeCopy = true);
	//@}


	//! \name Virtual functions override
	//@{
    //! plotting to EPS file
    virtual void PlotGfx(gfxinterface::CGfxInterface& gfx);
	virtual void UpdateExtent(gfxinterface::CGfxInterface& gfx);
	//@}

	//! \name Scripting methods
	//@{
	//! property enumeration
	enum ELine2DLODProp
	{
		Line2DLODPropUnknow,
		Line2DLODPropShrinkTol,
		Line2DLODPropShrinkNorm,
		Line2DLODPropShrinkPoint
	};
	PGL_DECLARE_SCRIPTING(Line2DLOD);
	//@}

	//! \name Serialization and debugging
	//@{
    //! Serialize functions
	void SerializeXML(CPGLArchive& ar);

    //! Debuggin functions
    #ifdef _DEBUG
        virtual void Dump( CDumpContext& dc ) const;
        virtual void AssertValid() const;    // Override
    #endif
	//@}
protected:
	virtual void PlotLineStripGfx(gfxinterface::CGfxInterface& gfx);
	virtual void PlotPointStripGfx(gfxinterface::CGfxInterface& gfx);
protected:
	//! \name Attributes
	//@{
	//! Line approximation object
	LineApprox m_hull;
	//@}
private:
	CPGLVectorFPtr m_pDPX;
	CPGLVectorFPtr m_pDPY;
};

PGL_DECLARE_SMARTPTR( CPGLLine2DLOD );

/*! \example lineLOD.cpp
Line and level of detail control using CPGLLine2DLOD.

\image html lineLOD.png "Level of detail with curves"
*/

#endif // !defined(AFX_PGLLINE2DLOD_H__56F09710_E27C_452B_A49B_78D72EAA6CB2__INCLUDED_)
